'''
Created on Jul 31, 2011

@author: kafkef
'''


import os
import zlib


from PyQt4.QtGui import *
from PyQt4.QtCore import SIGNAL, QDir, Qt, QVariant, QSettings, QString, QSize,\
                         QPoint
                         
from dexen.system import client
from dexen.system.client import db
from dexen.system.client.proxy import JobProxy
from dexen.system.client.controller.db_syncher import GetDBSyncher

job_proxy = None
svr_proxy = client.GetServerProxy()
db_syncher = GetDBSyncher()


class ArchiveListWidget(QListWidget):
    def __init__(self, parent=None):
        QListWidget.__init__(self, parent)


class ArchiveDialog(QDialog):
    def __init__(self, ind_ids, job_info, parent):
        super(ArchiveDialog, self).__init__(parent)
        self.ind_ids = ind_ids
        self.job_info = job_info
        self.svr_info = job_info.get_svr_info()
        self.job_proxy = svr_proxy.get_job_proxy(job_info)
        self._read_settings()
        self._setup_widgets()
    
    def _is_for_single_ind(self):
        return len(self.ind_ids) == 1
    
    def _setup_widgets(self):
        self.setModal(True)
        if self._is_for_single_ind():
            title = "Download/Export Archive - Single Ind"
        else:
            title = "Download/Export Archive - Multiple Inds"
        self.setWindowTitle(title)

        # Create the widgets
        self.archiveListWdg = ArchiveListWidget()
        self.selectAllCheckBox = QCheckBox("Select All")
        self.prependIdCheckBox = QCheckBox("Prepend Ind Id to each file")
        if not self._is_for_single_ind():
            self.prependIdCheckBox.setCheckState(Qt.Checked)
        self.createFolderCheckBox = QCheckBox("Create folder for each Ind")
        self.browseLabel = QLabel("Archive folder:")
        self.browseLineEdit = QLineEdit(self._load_rootdir())
        self.browseBtn = QPushButton("Browse")
        self.cancelBtn = QPushButton("Cancel")
        self.saveBtn = QPushButton("Save")

        # Setup layout
        vLayout = QVBoxLayout()
        
        if not self._is_for_single_ind():
            #vLayout.addWidget(QLabel("%d Inds selected"%(len(self.ind_ids))))
            pass
        else:
            vLayout.addWidget(QLabel("Ind %d - Archive items:"%(self.ind_ids[0])))
            vLayout.addWidget(self.selectAllCheckBox)
            vLayout.addWidget(self.archiveListWdg)
            self._initialize_content(self.ind_ids[0])
            self.connect(self.selectAllCheckBox, SIGNAL("stateChanged(int)"), 
                         self._selectAllCheckBox_stateChanged)
            if self.archiveListWdg.count() > 0:
                self.selectAllCheckBox.setCheckState(Qt.Checked)

        hLayout = QHBoxLayout()
        hLayout.addWidget(self.prependIdCheckBox)
        hLayout.addWidget(self.createFolderCheckBox)
        vLayout.addLayout(hLayout)

        hLayout = QHBoxLayout()
        hLayout.addWidget(self.browseLabel)
        hLayout.addWidget(self.browseLineEdit)
        hLayout.addWidget(self.browseBtn)
        vLayout.addLayout(hLayout)

        hLayout = QHBoxLayout()
        hLayout.addStretch()
        hLayout.addWidget(self.cancelBtn)
        hLayout.addWidget(self.saveBtn)
        vLayout.addLayout(hLayout)
        self.setLayout(vLayout)
        # Configure the signal/slots connections
        self.connect(self.saveBtn, SIGNAL("clicked()"), self.on_save)
        self.connect(self.browseBtn, SIGNAL("clicked()"), self.on_browseBtn_clicked)
        self.connect(self.cancelBtn, SIGNAL("clicked()"), self.close)
    
    def _selectAllCheckBox_stateChanged(self, state):
        for i in xrange(self.archiveListWdg.count()):
            item = self.archiveListWdg.item(i)
            assert isinstance(item, QListWidgetItem)
            item.setCheckState(state)
    
    def _initialize_content(self, ind_id):
        job_id = self.job_info.get_id() 
        svr_info = self.job_info.get_svr_info()
        assert isinstance(self.svr_info, db.ServerInfo)
        
        archive_names = []
        if not svr_info.is_connected():
            archive_names = db_syncher.get_ind_archive_names(ind_id, self.job_info)
        else:
            jobProxy = svr_proxy.get_job_proxy(self.job_info)
            assert isinstance(jobProxy, JobProxy)
            archive_names = jobProxy.get_ind_archive_names(ind_id)
            print "archive_names: ", archive_names
        
        for name in archive_names:
            item = QListWidgetItem(name)
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Unchecked)
            self.archiveListWdg.addItem(item)

    def get_content(self, ind_id, archive_name):
        job_id = self.job_info.get_id()
        content = db_syncher.get_ind_archive(ind_id, archive_name, self.job_info)
        
        if content is None and self.svr_info.is_connected():
            content = self.job_proxy.get_ind_archive(ind_id, archive_name)
            db_syncher.persist_ind_archive(ind_id, archive_name, content, 
                                           self.job_info, commit=False)
        if content:
            content = zlib.decompress(content)

        return content
    
    def _write_archive(self, ind_id, name, content):
        rootdir = str(self.browseLineEdit.text())
        path = rootdir
        
        if self.createFolderCheckBox.checkState() == Qt.Checked:
            ind_dirname = "Ind_{0}".format(ind_id)
            path = os.path.join(rootdir, ind_dirname)
            if not os.path.exists(path):
                os.mkdir(path)
        
        if self.prependIdCheckBox.checkState() == Qt.Checked:
            name = "Ind%d_"%(ind_id) + name
        
        f = open(os.path.join(path, name), "wb")
        f.write(content)
        f.close()
    
    def _get_archive_names(self, ind_id):
        job_id = self.job_info.get_id()
        if self._is_for_single_ind():
            archive_names = []
            for i in xrange(self.archiveListWdg.count()):
                item = self.archiveListWdg.item(i)
                assert isinstance(item, QListWidgetItem)
                if item.checkState() == Qt.Checked:
                    archive_names.append(str(item.text()))
            return archive_names
        # If for multiple individuals
        if svr_proxy.is_connected():
            return self.job_proxy.get_ind_archive_names(ind_id)
        # If svr is not connected
        return db_syncher.get_ind_archive_names(ind_id, self.job_info)
    
    def on_save(self):
        progressDlg = QProgressDialog("Exporting ind archives...", "Stop", 0, len(self.ind_ids), self)
        
        for index, ind_id in enumerate(self.ind_ids):
            progressDlg.setValue(index)
            if progressDlg.wasCanceled():
                break
            archive_names = self._get_archive_names(ind_id)
            for name in archive_names:
                content = self.get_content(ind_id, name)
                self._write_archive(ind_id, name, content)
        progressDlg.setLabelText("Saving archives to database...")
        db_syncher.commit()
        progressDlg.setValue(len(self.ind_ids))
        self.close()
    
    def on_browseBtn_clicked(self):
        rootdir = QFileDialog.getExistingDirectory(self, "Choose Directory",
                                                   self._load_rootdir(),
                                                   QFileDialog.ShowDirsOnly)
        if not os.path.exists(str(rootdir)): return
        self.browseLineEdit.setText(rootdir)
        self._save_rootdir(rootdir)
    
    def _load_rootdir(self):
        settings = QSettings()
        rootdir = settings.value("ArchiveDlg/RootDir", 
                                 QVariant(QDir.rootPath())).toString()
        if not os.path.exists(rootdir):
            return QDir.rootPath()    
        return rootdir
    
    def _save_rootdir(self, rootdir):
        settings = QSettings()
        rootdir = settings.setValue("ArchiveDlg/RootDir", rootdir) 

    def _read_settings(self):
        settings = QSettings()
        app_pos = qApp.activeWindow().pos()
        app_size = qApp.activeWindow().size()
        assert isinstance(app_pos, QPoint)
        assert isinstance(app_size, QSize)
        
        size = settings.value("ArchiveDlg/Size", QVariant(QSize(500, 300))).toSize()
        default_pos = QPoint()
        default_pos.setX(app_pos.x() + app_size.width()/2 - size.width()/2)
        default_pos.setY(app_pos.y() + app_size.height()/2 - size.height()/2)
        pos = settings.value("ArchiveDlg/Pos", QVariant(default_pos)).toPoint()
        
        #self.resize(size)
        #self.move(pos)
    
    def _write_settings(self):
        settings = QSettings()
        settings.setValue("ArchiveDlg/Pos", self.pos())
        settings.setValue("ArchiveDlg/Size", self.size())
        
    def closeEvent(self, event):
        self._write_settings()
        event.accept()

